程式碼連結
SMACSS - Module
進入主題
Module意思是一個獨立的CSS組件或單一元素, 被設定成模組的CSS組件會是獨立的,
不該綁定在父容器、ID選擇器、HTML元素,並同時能靈活套用至各頁面上`。
不要將CSS直接指定ID與HTML元素
這裡提出SMACSS所寫的範例Code,
如果今天你很確定在.fld裡面只會有一種span樣式這樣寫是ok的:
//HTML結構
<div class="fld">
<span>Folder Name</span>
</div>
//CSS樣式
.fld > span {
padding-left: 20px;
background: url(icon.png);
}
但假使你不能保證之後還會增加其他span樣式的話,像是這樣子:
<div class="fld">
<span>Folder Name</span>
<span>(32 items)</span>
</div>
你不就必須再回頭修改你的CSS設定?
其他HTML頁面早已套用舊CSS的話,
那更可怕的是你還必須回頭一一把所有的HTML修改為新架構,
專案越來越大時,程式碼彈性就會變得越來越低,
所以SMACSS會建議這樣寫:
//HTML結構
<div class="fld">
<span class="fld-name">Folder Name</span>
<span class="fld-items">(32 items)</span>
</div>
//CSS樣式
.fld{..}
.fld .fld-name{}
.fld .fld-items{}
所有樣式都指定class給HTML TAG,
這樣設計上有兩個好處:
1.不受HTML的全域樣式控制
如果你寫.fld span{..}的話,
意思即是在.fld的範圍內,
你的span都被該CSS設定所綁定住了,
假使今天.fld裡面要新增不同樣式的span,
你就只能用更高的權重來覆蓋掉他的樣式,
例如.fld span.box{..},
這樣子你的程式碼就會因覆蓋緣故變得更加得臃腫,
但如果你直接指定class給該元素的話,
像是
好處是新增其他的span標籤就變得很乾淨, 也解放了span讓它仍保持單純的inline排版元素,
新增class在span上都變得相當容易,
你也不用再去頭痛權重覆蓋的問題。
2.網頁SEO、HTML語意化更動變得更加靈活
像是上面的HTML結構是長成這樣。
<div class="fld">
<span class="fld-name">Folder Name</span>
<span class="fld-items">(32 items)</span>
</div>
假設在某頁上,.fld的區塊在這頁佔得權重較高,
我們便能夠很輕鬆地把它改成下面的HTML結構:
<article class="fld">
<h3 class="fld-name">Folder Name</h3>
<span class="fld-items">(32 items)</span>
</article>
看到這裡,
相信你就知道為什麼SMACSS不建議你直接將CSS樣式綁定在HTML tag或ID上面了,
原因自然是因為直接寫在class上,不論是要更動HTML結構或新增CSS樣式都變得更加靈活。
子模組(Subclassing Modules) 設計
在設計CSS模組時,
時常會遇到樣式臨時變動或新增的需求,
這時候就可以參考SMACSS的Subclassing Modules的觀念,
我們先來瀏覽下面的程式碼:
//設計一個.pod區塊,裡面的文字欄位佔了50%寬度
.pod {
width: 100%;
}
.pod input[type=text] {
width: 50%;
}
//設計到一半後,上面的模組要套用到#sidebar,且裡面input要改成100%時
//只好寫成下面這樣子來覆蓋上面模組
#sidebar .pod input[type=text] {
width: 100%;
}
這樣子寫法是相當不好的,
第一如果我今天不是要放在#sidebar,
而是要放在.main的區塊,設定也是裡面文字欄位是100%寬,
那你的Class也會因此越來越肥,如下程式碼:
#sidebar .pod input[type=text],.main .pod input[type=text] {
width: 100%;
}
更糟糕的事情是,
你的程式碼可讀性也會變得非常差,
這裡來舉個例子:
//寫好此模組設定
.pod {
width: 100%;
}
.pod input[type=text] {
width: 50%;
}
//寫到第三百行
//#sidebar裡面要用到.pod區塊,所以這樣子寫
#sidebar{..}
#sidebar a{..}
.#sidebar .pod input[type=text]{width: 100%; }
//又繼續寫了三百行
//.main又要設定.pod裡面文字欄位要100%時,就又必須回去追code,
//然後猶豫到底要放到最上面點.pod模組區塊,還是到#sidebar把class合併起來
//最後決定先在#sidebar那裡合併程式碼
.main{..}
.main ul{..}
.main li{..}
//隔天再來寫code,繼續寫了三百行,又有一樣東西要設定,
//就還得回想當初是在哪裡有寫過這行程式碼,還是不管它直接寫在.block裡面。
.block{}
.block .pod input[type=text] { width: 100%; }
//專案第六十天你已經不知道你的CSS在寫些什麼鬼東西了
為了避免這樣的事情發生,
SMACSS的Subclassing Modules 建議你這樣子寫:
//CSS樣式
.pod {
width: 100%;
}
.pod input[type=text] {
width: 50%;
}
.pod-constrained input[type=text] {
width: 100%;
}
.pod-callout {
width: 200px;
}
.pod-callout input[type=text] {
width: 180px;
}
//HTML結構
<div class="pod pod-constrained">...</div>
<div class="pod pod-callout">...</div>
兩行HTML都載入了.pod的class,
讓網頁版型先吃到預設樣式,
如果今天裡面的按鈕要改成100%,
那就再增加子模組class.pod-constrained,
這樣就能夠覆蓋掉.pod的input設定。
如果你的.pod的寬度必須調整,
那你也可以透過子模組class.pod-callout來覆蓋.pod,
Subclassing Modules利用CSS覆蓋、HTML可以載入多個Class的原理,
讓我們只要回到模組的class新增子模組滿足條件覆蓋樣式。
這樣子整個邏輯就可以都依照著.pod的模組區塊來延伸子模組,
不會又因為其他頁面的class區塊更動了模組設定而猶豫該怎麼寫。
單一元素模組設定
這個是我自己補充模組的部分,
當我還是菜鳥的時候,我會這樣來設計一個按鈕:
//HTML結構
<div class="row">
<input type="button" value="">
</div>
//css程式碼
.row{
text-align: center;
}
.row input{
css按鈕樣式程式碼
}
這樣的程式碼確實能吃到樣式,
但它的彈性就會變得非常非常得差,
如果.row這個div裡面又要放其他input元素,
而且樣式完全不一樣,你不就得CSS和HTML的架構都得全改,
更別說專案在執行過程中,你已經設計好幾百頁HTML,
結果又必須重新回頭去修改HTML設定,
所以請盡量不要直接綁HTML tag,
每次美術和我說它不會改畫面,
那裡就一定只會有那個元素,
我也就很開心得下了這樣的語法, 但到後來改得機率都是高達99.9999%....OTZ,
於是乎我就都改寫成這樣的寫法了:
//HTML結構
<div class="row">
<input type="button" class="btn" value="">
</div>
//css程式碼
.row{
text-align: center;
}
.btn{
css按鈕樣式程式碼
}
你可以從上面的程式碼看得出來,
我的按鈕直接指定一個class樣式,
不依附在父元素上面,
所以今天你要在各個頁面上套用這個按鈕樣式時,
就只要在input上面加上btn的class就好。
這樣就可以做到SMACSS所提倡的觀念,
也就是Module要設計為獨立的樣式, 不該綁定在父容器、ID選擇器、HTML元素,並同時能靈活套用至各頁面上。